#include <boost/lexical_cast.hpp>
    
namespace gen {

    ///////////////////////////////////////////////////////////////////////////
    //
    //  char_generator class
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename DerivedT>
    template <typename InfoT>
	void
	char_generator<DerivedT>::generate(InfoT & info) const
    {
		info.append(this->derived().get());
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  chlit class
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename CharT>
    inline chlit<CharT>
    ch_g(CharT ch)
    { 
        return chlit<CharT>(ch); 
    }

    // This should take care of ch_g("a") "bugs"
    template <typename CharT, std::size_t N>
    inline chlit<CharT>
    ch_g(CharT const (& str)[N])
    {
        //  ch_p's argument should be a single character or a null-terminated
        //  string with a single character
        BOOST_STATIC_ASSERT(N < 3);
        return chlit<CharT>(str[0]);
    }

	///////////////////////////////////////////////////////////////////////////
    //
    //  chseq class
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename CharIteratorT>
    template <typename InfoT>
    inline void
	chseq<CharIteratorT>::generate(InfoT & info) const
    {
        typedef typename generator_string<typename InfoT::char_t>::str_type		result_t;

		info.append(result_t(first, last));
    }

    template <typename CharT>
    inline chseq<CharT const*>
    chseq_g(CharT const* str)
    { 
        return chseq<CharT const*>(str); 
    }

    template <typename CharIteratorT>
    inline chseq<CharIteratorT>
    chseq_g(CharIteratorT first, CharIteratorT last)
    { 
        return chseq<CharIteratorT>(first, last); 
    }

	// This should take care of string
    template <typename CharIteratorT>
    template <typename InfoT>
    inline void
	chseq< basic_string<CharIteratorT> >::generate(InfoT & info) const
    {
        typedef typename generator_string<typename InfoT::char_t>::str_type		result_t;

		info.append(result_t(ptr.get(), last));
    }

	template <typename CharT>
    inline chseq< basic_string<CharT> >
    chseq_g(basic_string<CharT> str)
	{
		return chseq< basic_string<CharT> >(str);
	}

    ///////////////////////////////////////////////////////////////////////////
    //
    //  strlit class
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename CharIteratorT>
	template <typename InfoT>
	inline void
	strlit<CharIteratorT>::generate(InfoT & info) const
	{
		seq.generate(info);
	}

    template <typename CharT>
    inline strlit<CharT const*>
    str_g(CharT const* str)
    { 
        return strlit<CharT const*>(str); 
    }

    template <typename CharT>
    inline strlit<CharT *>
    str_g(CharT * str)
    { 
        return strlit<CharT *>(str); 
    }

    // This should take care of str_g('a') "bugs"
    template <typename CharT>
    inline chlit<CharT>
    str_g(CharT ch)
    {
        return chlit<CharT>(ch);
    }

    // This should take care of "string"
    template <typename CharT>
    inline strlit< basic_string<CharT> >
    str_g(basic_string<CharT> str)
    { 
        return strlit< basic_string<CharT> >(str); 
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  upper class
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename CharIteratorT>
	template <typename InfoT>
	inline void
	upperlit<CharIteratorT>::generate(InfoT & info) const
	{
		typename chseq<CharIteratorT>::char_iterator_t i;
		for (i = seq.first; i<seq.last; ++i)
		{
			if (i >= seq.first+m_start && i<seq.first+m_start+m_length)
			{
				info.append(chr::toupper_(*i));
			}
			else info.append(*i);
		}

	}

    template <typename CharT>
    inline upperlit<CharT const*>
    upper_str(CharT const* str, size_t start, size_t length)
    { 
        return upperlit<CharT const*>(str, start, length); 
    }

    template <typename CharT>
    inline upperlit<CharT *>
    upper_str(CharT * str, size_t start, size_t length)
    { 
        return upperlit<CharT *>(str, start, length); 
    }

	// This should take care of string
	template <typename CharT>
    inline upperlit< basic_string<CharT> >
    upper_str(basic_string<CharT> str, size_t start, size_t length)
    { 
        return upperlit< basic_string<CharT> >(str, start, length); 
    }

    template <typename CharT>
    inline upperch<CharT>
    upper_str(CharT ch)
    { 
        return upperch<CharT>(ch); 
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  upper_generator class
    //
    ///////////////////////////////////////////////////////////////////////////

    template <typename S>
	template <typename InfoT>
	inline void
	upper_generator<S>::generate(InfoT & info) const
	{
		InfoT tmpInfo = info;
		tmpInfo.reset(typename InfoT::str_t());
		this->subject().generate(tmpInfo);	
		upper_str(tmpInfo.str(), m_start, m_length).generate(info);
	}

	// This should take care of generator
    template <typename S>
    inline upper_generator<S>
	upper_g(generator<S> const& a, size_t start, size_t length)
    {
        return upper_generator<S>(a.derived(), start, length);
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  lower class
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename CharIteratorT>
	template <typename InfoT>
	inline void
	lowerlit<CharIteratorT>::generate(InfoT & info) const
	{
		typename chseq<CharIteratorT>::char_iterator_t i;
		for (i = seq.first; i<seq.last; ++i)
		{
			if (i >= seq.first+m_start && i<seq.first+m_start+m_length)
			{
				info.append(chr::tolower_(*i));
			}
			else info.append(*i);
		}
	}

    template <typename CharT>
    inline lowerlit<CharT const*>
    lower_str(CharT const* str, size_t start, size_t length)
    { 
        return lowerlit<CharT const*>(str, start, length); 
    }

    template <typename CharT>
    inline lowerlit<CharT *>
    lower_str(CharT * str, size_t start, size_t length)
    { 
        return lowerlit<CharT *>(str, start, length); 
    }

	// This should take care of string
	template <typename CharT>
    inline lowerlit< basic_string<CharT> >
    lower_str(basic_string<CharT> str, size_t start, size_t length)
    { 
        return lowerlit< basic_string<CharT> >(str, start, length); 
    }

    template <typename CharT>
    inline lowerch<CharT>
    lower_str(CharT ch)
    { 
        return lowerch<CharT>(ch); 
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  lower_generator class
    //
    ///////////////////////////////////////////////////////////////////////////

    template <typename S>
	template <typename InfoT>
	inline void
	lower_generator<S>::generate(InfoT & info) const
	{
		InfoT tmpInfo = info;
		tmpInfo.reset(typename InfoT::str_t());
		this->subject().generate(tmpInfo);	
		lower_str(tmpInfo.str(), m_start, m_length).generate(info);
	}

	// This should take care of generator
    template <typename S>
    inline lower_generator<S>
	lower_g(generator<S> const& a, size_t start, size_t length)
    {
        return lower_generator<S>(a.derived(), start, length);
    }

	///////////////////////////////////////////////////////////////////////////
    //
    //  varstr class
    //
    ///////////////////////////////////////////////////////////////////////////  
    template <typename CharIteratorT>
	template <typename InfoT>
	inline void
	varstr<CharIteratorT>::generate(InfoT & info) const
	{
		static char_t delim = (char_t)'$';
		char_iterator_t p, n, s;
		for (p = seq.first; p < seq.last; ++p)
		{
			// find the first '$'
			if (*p==delim) {
				n = p+1;
				while (n<seq.last && *n!=delim) n++;
				// find the second '$'
				if (*n==delim) {
					typedef vector<fmtstr>::iterator	iterator;
					// search special format to_lower or to_upper
					s = p+1;
					vector<fmtstr> formattings = parse_fmt(s, n);
					try
					{
						string val(s,n);
						size_t n_arg = boost::lexical_cast<int>( val );
						if (n_arg<info.argc()) {
							abstract_generator<InfoT>* ptr = any_convert::to<InfoT>(info.argv(n_arg));
							InfoT tmp_context = info;
							tmp_context.reset();
							// get the result string
							if (ptr) ptr->do_generate_virtual(tmp_context);
							for (iterator i=formattings.begin(); i<formattings.end(); ++i)
							{
								// to_lower or to_upper
								switch (i->type) {
								case fmtlower:
									{
										lowerlit<typename InfoT::str_t> lstr(tmp_context.str(),i->start, i->end);
										tmp_context.reset();
										lstr.generate(tmp_context);
									}
									break;
								case fmtupper:
									{
										upperlit<typename InfoT::str_t> ustr(tmp_context.str(),i->start, i->end);
										tmp_context.reset();
										ustr.generate(tmp_context);
									}
									break;
								default:
									break;
								}
							}
							// add to context
							info.append(tmp_context.str());
						}
						// next loop
						p = n;
						continue;
					}
					catch(boost::bad_lexical_cast &)
					{}
				}
			} 
			// others cases : add the character to context
			info.append(*p);
		}
	}

	template <typename CharIteratorT>
	vector<fmtstr> 
	varstr<CharIteratorT>::parse_fmt(char_iterator_t & p, char_iterator_t n) const
	{
		vector<fmtstr> formattings;
		static char_t fmt_char[2] = {(char_t)'L', (char_t)'U'};
		static char_t fmt_delim[3] = {(char_t)'[', (char_t)',', (char_t)']'};
		static char_t fmt_space[2] = {(char_t)' ', (char_t)'\t'};
		for (; p < n; ++p)
		{
			// read space
			while (*p==fmt_space[0] || *p==fmt_space[1]) p++;
			// find format
			if (*p==fmt_char[0] || *p==fmt_char[1]) {
				fmttype type = (*p==fmt_char[0])? fmtlower: fmtupper;
				size_t start = 0;
				size_t end = string::npos;
				if (*(p+1)==fmt_delim[0]) {
					char_iterator_t m = p+1, r = p+1;
					while (m<n && *m!=fmt_delim[1]) m++;
					while (r<n && *r!=fmt_delim[2]) r++;
					if (*r==fmt_delim[2]) {
						if (m>r) m=r;
						try
						{
							string val(p+2,m);
							start = boost::lexical_cast<int>( val );
						}
						catch(boost::bad_lexical_cast &)
						{}
						if (m!=r) {
							try
							{
								string val(m+1,r);
								end = boost::lexical_cast<int>( val );
							}
							catch(boost::bad_lexical_cast &)
							{}
						}
						p = r;
					}
					else {
						break;
					}
				}
				formattings.push_back(fmtstr(type, start, end));
			} 
			else {
				break;
			}
		}
		return formattings;
	}
}
